package easier.app.x.result;

import android.app.Activity;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.PowerManager;
import android.provider.Settings;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
import androidx.activity.result.contract.ActivityResultContracts.TakePicture;
import androidx.activity.result.contract.ActivityResultContracts.TakePicturePreview;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import easier.app.x.CommonCode;
import easier.app.x.result.ResultFragment.Builder;
import easier.app.x.starter.IntentBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

/**
 * 构建
 */
public class ResultFragmentFactory {

    /**
     * 构造请求权限
     *
     * @param permission 权限
     * @param callBack   回调
     *
     * @return 请求
     */
    public static ResultFragment< String, Boolean > buildPermission( String permission,
        ActivityResultCallback< Boolean > callBack ) {

        return ResultFragment.newInstance( new Builder< String, Boolean >() {
            @Override
            public ActivityResultContract< String, Boolean > createContract() {

                return new ActivityResultContracts.RequestPermission();
            }

            @Override
            public ActivityResultCallback< Boolean > getResultCallback() {

                return callBack;
            }

            @Override
            public String createInput() {

                return permission;
            }
        } );
    }

    /**
     * 构造请求权限
     *
     * @param permission 权限
     * @param callBack   回调
     *
     * @return 请求
     */
    public static ResultFragment< String[], java.util.Map< String, Boolean > > buildPermissions(
        String[] permission,
        ActivityResultCallback< Map< String, Boolean > > callBack ) {

        return ResultFragment.newInstance( new Builder< String[], java.util.Map< String, Boolean > >() {
            @Override
            public ActivityResultContract< String[], java.util.Map< String, Boolean > > createContract() {

                return new ActivityResultContracts.RequestMultiplePermissions();
            }

            @Override
            public ActivityResultCallback< java.util.Map< String, Boolean > > getResultCallback() {

                return callBack;
            }

            @Override
            public String[] createInput() {

                return permission;
            }
        } );
    }

    public static ResultFragment< Void, Void > buildNotificationSetting( Context context,
        ActivityResultCallback< Boolean > callback ) {

        return ResultFragment.newInstance( new Builder< Void, Void >() {
            @Override
            public ActivityResultContract< Void, Void > createContract() {

                return new ActivityResultContract< Void, Void >() {
                    @NonNull
                    @Override
                    public Intent createIntent( @NonNull Context context, Void input ) {

                        Intent intent = new Intent();
                        if ( VERSION.SDK_INT >= VERSION_CODES.O ) {
                            intent.setAction( Settings.ACTION_APP_NOTIFICATION_SETTINGS );
                            //这种方案适用于 API 26, 即8.0（含8.0）以上可以用
                            intent.putExtra( Settings.EXTRA_APP_PACKAGE, context.getPackageName() );
                            intent.putExtra( Settings.EXTRA_CHANNEL_ID, context.getApplicationInfo().uid );

                            //这种方案适用于 API21——25，即 5.0——7.1 之间的版本可以使用
                            intent.putExtra( "app_package", context.getPackageName() );
                            intent.putExtra( "app_uid", context.getApplicationInfo().uid );

                            ComponentName componentName = intent.resolveActivity( context.getPackageManager() );
                            if ( componentName != null ) {
                                return intent;
                            } else {
                                intent.setAction( Settings.ACTION_APPLICATION_DETAILS_SETTINGS );
                                Uri uri = Uri.fromParts( "package", context.getPackageName(), null );
                                intent.setData( uri );
                                return intent;
                            }
                        } else {
                            return IntentBuilder.appSettingIntent( context );
                        }
                    }

                    @Override
                    public Void parseResult( int resultCode, @Nullable Intent intent ) {

                        return null;
                    }
                };
            }

            @Override
            public ActivityResultCallback< Void > getResultCallback() {

                return new ActivityResultCallback< Void >() {
                    @Override
                    public void onActivityResult( Void result ) {

                        if ( callback != null ) {
                            callback.onActivityResult( CommonCode.areNotificationsEnabled( context ) );
                        }
                    }
                };
            }

            @Override
            public Void createInput() {

                return null;
            }
        } );
    }

    @RequiresApi( api = VERSION_CODES.M )
    public static ResultFragment< Void, Void > buildBatteryOptimizations( ActivityResultCallback< Void > callback ) {

        return ResultFragment.newInstance( new Builder< Void, Void >() {
            @Override
            public ActivityResultContract< Void, Void > createContract() {

                return new ActivityResultContract< Void, Void >() {
                    @NonNull
                    @Override
                    public Intent createIntent( @NonNull Context context, Void input ) {

                        Intent intent = new Intent();
                        String packageName = context.getPackageName();
                        PowerManager pm = (PowerManager) context.getSystemService( Context.POWER_SERVICE );

                        if ( pm.isIgnoringBatteryOptimizations( packageName ) ) {
                            intent.setAction( Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS );
                        } else {
                            intent.setAction( Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS );
                            intent.setData( Uri.parse( "package:" + packageName ) );
                        }

                        return intent;
                    }

                    @Override
                    public Void parseResult( int resultCode, @Nullable Intent intent ) {

                        return null;
                    }
                };
            }

            @Override
            public ActivityResultCallback< Void > getResultCallback() {

                return callback;
            }

            @Override
            public Void createInput() {

                return null;
            }
        } );
    }

    public static ResultFragment< Void, Void > buildAppSettings( ActivityResultCallback< Void > callback ) {

        return ResultFragment.newInstance( new Builder< Void, Void >() {
            @Override
            public ActivityResultContract< Void, Void > createContract() {

                return new ActivityResultContract< Void, Void >() {
                    @NonNull
                    @Override
                    public Intent createIntent( @NonNull Context context, Void input ) {

                        return IntentBuilder.appSettingIntent( context );
                    }

                    @Override
                    public Void parseResult( int resultCode, @Nullable Intent intent ) {

                        return null;
                    }
                };
            }

            @Override
            public ActivityResultCallback< Void > getResultCallback() {

                return callback;
            }

            @Override
            public Void createInput() {

                return null;
            }
        } );
    }

    /**
     * @param callback 获取图片
     *
     * @return
     */
    public static ResultFragment< String, Uri > buildGetContentPicture( ActivityResultCallback< Uri > callback ) {

        return ResultFragment.newInstance( new Builder< String, Uri >() {
            @Override
            public ActivityResultContract< String, Uri > createContract() {

                return new GetContent();
            }

            @Override
            public ActivityResultCallback< Uri > getResultCallback() {

                return callback;
            }

            @Override
            public String createInput() {

                return "image/*";
            }
        } );
    }

    /**
     * copy from {@link androidx.activity.result.contract.ActivityResultContracts.GetContent}
     */
    public static class GetContent extends ActivityResultContract< String, Uri > {

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent( @NonNull Context context, @NonNull String input ) {

            Intent intent = new Intent( Intent.ACTION_PICK );
            intent.setType( "image/*" );

            ComponentName componentName = intent.resolveActivity( context.getPackageManager() );
            if ( componentName != null ) {
                return intent;
            }

            return new Intent( Intent.ACTION_GET_CONTENT )
                .addCategory( Intent.CATEGORY_OPENABLE )
                .setType( input );
        }

        @Nullable
        @Override
        public final SynchronousResult< Uri > getSynchronousResult( @NonNull Context context,
            @NonNull String input ) {

            return null;
        }

        @Nullable
        @Override
        public final Uri parseResult( int resultCode, @Nullable Intent intent ) {

            if ( intent == null || resultCode != Activity.RESULT_OK ) {
                return null;
            }
            return intent.getData();
        }
    }

    public static ResultFragment< String, List< Uri > > buildMultipleGetContentPicture(
        ActivityResultCallback< List< Uri > > callback ) {

        return ResultFragment.newInstance( new Builder< String, List< Uri > >() {
            @Override
            public ActivityResultContract< String, List< Uri > > createContract() {

                return new GetMultipleContents();
            }

            @Override
            public ActivityResultCallback< List< Uri > > getResultCallback() {

                return callback;
            }

            @Override
            public String createInput() {

                return "image/*";
            }
        } );
    }

    /**
     * copy from {@link androidx.activity.result.contract.ActivityResultContracts.GetMultipleContents}
     */
    public static class GetMultipleContents extends ActivityResultContract< String, List< Uri > > {

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent( @NonNull Context context, @NonNull String input ) {

            Intent intent = new Intent( Intent.ACTION_PICK );
            intent.setType( "image/*" );
            intent.putExtra( Intent.EXTRA_ALLOW_MULTIPLE, true );

            ComponentName componentName = intent.resolveActivity( context.getPackageManager() );
            if ( componentName != null ) {
                return intent;
            }

            return new Intent( Intent.ACTION_GET_CONTENT )
                .addCategory( Intent.CATEGORY_OPENABLE )
                .setType( input )
                .putExtra( Intent.EXTRA_ALLOW_MULTIPLE, true );
        }

        @Nullable
        @Override
        public final SynchronousResult< List< Uri > > getSynchronousResult( @NonNull Context context,
            @NonNull String input ) {

            return null;
        }

        @NonNull
        @Override
        public final List< Uri > parseResult( int resultCode, @Nullable Intent intent ) {

            if ( intent == null || resultCode != Activity.RESULT_OK ) {
                return Collections.emptyList();
            }
            return getClipDataUris( intent );
        }

        @NonNull
        static List< Uri > getClipDataUris( @NonNull Intent intent ) {
            // Use a LinkedHashSet to maintain any ordering that may be
            // present in the ClipData
            LinkedHashSet< Uri > resultSet = new LinkedHashSet<>();
            if ( intent.getData() != null ) {
                resultSet.add( intent.getData() );
            }
            ClipData clipData = intent.getClipData();
            if ( clipData == null && resultSet.isEmpty() ) {
                return Collections.emptyList();
            } else if ( clipData != null ) {
                for ( int i = 0; i < clipData.getItemCount(); i++ ) {
                    Uri uri = clipData.getItemAt( i ).getUri();
                    if ( uri != null ) {
                        resultSet.add( uri );
                    }
                }
            }
            return new ArrayList<>( resultSet );
        }
    }

    public static ResultFragment< Void, Bitmap > buildTakePhotoPreview( ActivityResultCallback< Bitmap > callback ) {

        return ResultFragment.newInstance( new Builder< Void, Bitmap >() {
            @Override
            public ActivityResultContract< Void, Bitmap > createContract() {

                return new TakePicturePreview();
            }

            @Override
            public ActivityResultCallback< Bitmap > getResultCallback() {

                return callback;
            }

            @Override
            public Void createInput() {

                return null;
            }
        } );
    }

    public static ResultFragment< Uri, Boolean > buildTakePhoto( Uri fileUri, ActivityResultCallback< Uri > callback ) {

        return ResultFragment.newInstance( new Builder< Uri, Boolean >() {
            @Override
            public ActivityResultContract< Uri, Boolean > createContract() {

                return new TakePicture();
            }

            @Override
            public ActivityResultCallback< Boolean > getResultCallback() {

                return new ActivityResultCallback< Boolean >() {
                    @Override
                    public void onActivityResult( Boolean result ) {

                        if ( result ) {
                            callback.onActivityResult( fileUri );
                        } else {
                            callback.onActivityResult( null );
                        }
                    }
                };
            }

            @Override
            public Uri createInput() {

                return fileUri;
            }
        } );
    }

    public static ResultFragment< Intent, ActivityResult > buildRegisterForActivityResult(
        Intent intent,
        ActivityResultCallback< ActivityResult > callback ) {

        return ResultFragment.newInstance( new Builder< Intent, ActivityResult >() {
            @Override
            public ActivityResultContract< Intent, ActivityResult > createContract() {

                return new StartActivityForResult();
            }

            @Override
            public ActivityResultCallback< ActivityResult > getResultCallback() {

                return callback;
            }

            @Override
            public Intent createInput() {

                return intent;
            }
        } );
    }
}
